<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="../lib/jq.js"></script>
  <script src="../lib/vue.js"></script>
  <script src="../lib/socket-client.js"></script>
  <script src="../lib/easel.js"></script>
  <script src="../lib/tween.js"></script>
  <style>
    canvas {
      position: fixed;
      right: 0;
      top: 0;
      border: 1px solid black;
      pointer-events: none;
    }

    body {
      overflow: hidden;
    }

    .player {
      width: 15px;
      height: 15px;
      border-radius: 50%;
      display: inline-block;
    }
  </style>
</head>

<body>
  <div class="app">
    <h2>操作记录</h2>
    <div class="info">
      <i v-if="linkStatus">你的名称: {{ username }}</i>
      <i class="get">每秒下载包: <span>{{ frameNum }}</span></i>
      <i class="get">每秒上传包: <span>{{ frameUploadNum }}</span></i>
      <i class="playerNum">玩家数: <span>{{ info.playerNum }}</span></i>
      <button v-if="linkStatus" @click="disconnect">断开游戏</button>
    </div>
    <div v-if="!linkStatus">
      <input v-if="!linkStatus" type="text" v-model="username" @keyup.enter="link" placeholder="输入你的名称">
      <input v-if="!linkStatus" type="color" v-model='color'>
      <button v-if="!linkStatus" @click="link">点击链接游戏</button>
    </div>
    <div v-if="!linkStatus">
      <input type="text" placeholder="指定开始帧" v-model="playLog">
      <input type="number" v-model="playX" placeholder="播放速度倍速">
      <button @click="gameLog">查看游戏记录</button>
      <i v-if="getLogStatus">加载游戏记录中</i>
      <div v-if="logs.length">
        游戏记录: <span>{{ playLog }}</span> / <span>{{ logs.length }}</span>
      </div>
    </div>
    <ul>
      <li v-for="item in server" v-html='item'>
      </li>
    </ul>
    <h2>说明</h2>
    <div>
      <p>输入名称回车进入画板</p>
      <p>↑↓←→移动</p>
      <p>按住D画画</p>
      <p>按下C清除</p>
    </div>
  </div>
  <canvas id="app" width="1200" height="800"></canvas>

  <script>
    let stage = new createjs.Stage('app');
    // stage.autoClear = false;

    class Game {
      constructor() {
        this.players = {};

        this.run();
        this.upload(60);
      }

      run() {
        createjs.Ticker.timingMode = createjs.Ticker.RAF;
        createjs.Ticker.addEventListener('tick', () => {
          stage.update();
          // this.players.map(i => i.move());
        })
      }

      upload(num) {
        setInterval(() => {
          if (!vm.io) return;
          let me = this.players[vm.io.id];
          if (!me) return;
          vm.io.emit('uploadData', {
            x: me.x,
            y: me.y
          })
          vm.frameUploadNumb++;
        }, 1000 / num);
      }

      add(item) {
        if (!item.id || this.players[item.id]) return;
        this.players[item.id] = new Player(item);
        vm.server.unshift(
          `玩家${this.players[item.id].username}加入游戏`
        )
      }

      leave(item) {
        if (!this.players[item.id]) return;
        this.players[item.id].leave();
        vm.server.unshift(
          `玩家${this.players[item.id].username}离开游戏`
        )
        delete this.players[item.id];
      }

      get(id) {
        if (!this.players[id]) return;
        return this.players[id];
      }

      move(id, data, time) {
        if (!this.players[id]) return;
        this.players[id].action(data, time, id);
      }

      complete(data) {
        switch (data.action) {
          case 'info':
            vm.info = data;
            // if (data.addUser) {
            //   // data.allPlayerId.map(arr => {
            //   //   game.add(arr[0], arr[1]);
            //   // })
            //   vm.server.unshift(
            //     `玩家${data.username}加入游戏` + (data.id == vm.io.id ? " - me" : '')
            //   )
            //   console.log(data)
            //   game.add(data);
            // }
            // if (data.leaveUser) {
            //   vm.server.unshift(
            //     `玩家${data.leaveUser}离开游戏`
            //   )
            //   game.leave(data.id);
            // }
            break;
          case 'addPlayer':
            game.add(data.data);
            break;
          case 'leavePlayer':
            game.leave(data);
            break;
          case 'basicPlayer':
            let playerNames = [];
            data.allPlayerData.map(item => {
              playerNames.push(item.username);
              game.add(item);
            });
            vm.server.unshift(
              `该房间中存在(${playerNames.join(', ')})`
            );
            break;
          case 'operaction':
            vm.frameId = data.data[0];
            data.data.slice(1).map(item => {
              game.move(item[1], item[0], data.time);
            })
            break;
        }

        vm.frameNumB++;
        Object.keys(game.players).forEach(key => {
          game.players[key].move();
        });
      }
    }

    class Player {
      constructor({
        id,
        color,
        x,
        y,
        username
      }) {
        this.x = x || 100;
        this.y = y || 100;
        this.moveX = 0;
        this.moveY = 0;
        this.id = id;
        this.color = color;
        this.username = username || 'null';
        this.addSpeed = 0;
        this.speed = 10;
        this.draw = false;

        this.oldX = this.x;
        this.oldY = this.y;

        this.create();
      }

      create() {
        this.container = new createjs.Container();
        this.circle = new createjs.Shape();
        this.line = new createjs.Shape();
        this.circle.graphics.beginFill(this.color).drawCircle(0, 0,
          10);
        this.container.addChild(this.circle);
        stage.addChild(this.container);
        stage.addChild(this.line);
        this.container.x = this.x;
        this.container.y = this.y;
      }

      leave() {
        stage.removeChild(this.container);
      }

      move() {
        if (this.addSpeed) {
          this.speed = 30;
        } else {
          this.speed = 10;
        }

        this.x += this.moveX * this.speed;
        this.y += this.moveY * this.speed;

        createjs.Tween.get(this.container)
          .to({
            y: this.y,
            x: this.x
          }, 1000 / (20 * vm.playX))
          .addEventListener('change', ev => {
            if (this.draw) {
              this.line.graphics.setStrokeStyle(20, 'round').beginStroke(this.color).moveTo(this.container.x, this
                .container
                .y).curveTo(this.container.x, this.container.y, this.oldX, this.oldY);
              stage.addChild(this.line);
            }

            this.oldX = this.container.x;
            this.oldY = this.container.y;
          })

        stage.addChild(this.container)
      }

      action(data, time, id) {
        data.map(ac => {
          vm.server.unshift(
            `玩家${this.username.slice(0, 10)} <span class="player" style="background:${game.get(id).color}"></span> 操作${ac} - ` +
            (new Date().getTime() - time) +
            'ms - 操作帧: ' + vm.frameId);
          switch (ac) {
            case 'left':
              this.moveX = -1;
              break;
            case 'right':
              this.moveX = 1;
              break;
            case 'top':
              this.moveY = -1;
              break;
            case 'bottom':
              this.moveY = 1;
              break;
            case 'leftup':
              this.moveX = 0;
              break;
            case 'rightup':
              this.moveX = 0;
              break;
            case 'topup':
              this.moveY = 0;
              break;
            case 'bottomup':
              this.moveY = 0;
              break;
            case 'addSpeed':
              this.addSpeed = true;
              break;
            case 'addSpeedup':
              this.addSpeed = false;
              break;
            case 'draw':
              this.draw = true;
              break;
            case 'drawup':
              this.draw = false;
              break;
            case 'clear':
              // stage.removeChild(this.line)
              this.line.graphics.clear();
              break;
          }
        })
      }
    }

    function getRandom(num) {
      return ~~(Math.random() * num);
    }

    let game = new Game;

    let vm = new Vue({
      el: '.app',
      data: {
        server: [],
        io: null,
        linkStatus: false,
        username: '',
        frameNum: 0,
        frameNumB: 0,
        frameId: 0,
        frameUploadNum: 0,
        frameUploadNumb: 0,
        getLogStatus: false,
        logs: [],
        playLog: 0,
        playX: 1,
        color: `#${new Array(6).fill().map(i => getRandom(9)).join('')}`,

        info: {}
      },
      methods: {
        link() {
          if (this.username == '' || this.playStatus) return;
          this.add();
        },
        disconnect() {
          this.linkStatus = false;
          this.io.emit('leave')
        },
        bindEvent() {
          this.io.on('connect', () => {
            console.log('连接服务器成功');

            this.io.on('all', data => {
              if (this.playStatus) return;
              game.complete(data)
            })
            this.io.on('getGameLog', data => {
              this.getLogStatus = false;
              if (this.playLog < this.logs.length && this.playLog != 0) return;
              this.logs = data;
              this.play();
            })
          })
        },
        play() {
          if (this.playLog >= this.logs.length) {
            this.playStatus = false;
            return;
          }
          this.playStatus = true;
          let item = this.logs[this.playLog];
          game.complete(item);

          this.playLog++;
          setTimeout(this.play.bind(this), 1000 / (20 * this.playX));
        },
        add() {
          this.io.emit('add', {
            username: this.username,
            color: this.color,
            id: this.io.id
          });
          this.io.on('add', () => {
            this.linkStatus = true;
          })

          document.body.addEventListener('keydown', ev => {
            let code = ev.keyCode - 37;
            let action = ['left', 'top', 'right', 'bottom'];
            if (code >= 0 && code <= 3) {
              this.io.emit('action', {
                action: action[code]
              })
            }
            if (code == -5) {
              this.io.emit('action', {
                action: 'addSpeed'
              })
            }
            if (code == 31) {
              this.io.emit('action', {
                action: 'draw'
              })
            }
            if (code == 30) {
              this.io.emit('action', {
                action: 'clear'
              })
            }
          })
          document.body.addEventListener('keyup', ev => {
            let code = ev.keyCode - 37;
            let action = ['left', 'top', 'right', 'bottom'];
            if (code >= 0 && code <= 3) {
              this.io.emit('action', {
                action: action[code] + 'up'
              })
            }
            if (code == -5) {
              this.io.emit('action', {
                action: 'addSpeedup'
              })
            }
            if (code == 31) {
              this.io.emit('action', {
                action: 'drawup'
              })
            }
          })
        },
        gameLog() {
          this.getLogStatus = true;
          this.io.emit('getGameLog');
        }
      },
      mounted() {
        this.io = io('http://192.168.42.107:3001');
        this.bindEvent();
        setInterval(() => {
          this.frameNum = this.frameNumB;
          this.frameNumB = 0;

          this.frameUploadNum = this.frameUploadNumb;
          this.frameUploadNumb = 0;

          if (this.server.length >= 100) {
            this.server.splice(50, 100);
          }
        }, 1000);
      }
    })
  </script>
</body>

</html>